/********************************** (C) COPYRIGHT *******************************
 * File Name          : main.c
 * Author             : WCH
 * Version            : V1.0.0
 * Date               : 2023/12/25
 * Description        : Main program body.
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

/*
 *@Note
 *Multiprocessor communication mode routine:
 *Master:USART1_Tx(PD5)\USART1_Rx(PD6).
 *This routine demonstrates that USART1 receives the data sent by CH341 and inverts
 *it and sends it (baud rate 115200).
 *
 *Hardware connection:PD5 -- Rx
 *                    PD6 -- Tx
 *
 */

#include "debug.h"


/* Global define */
#include "main.h"

#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define SET_PWM_CH1(NUM)     TIM2->CH1CVR = NUM
#define SET_PWM_CH2(NUM)     TIM2->CH2CVR = NUM
#define SET_PWM_CH4(NUM)     TIM2->CH4CVR = NUM

#define SET_FAN_PWMCCR(NUM)  SET_PWM_CH1(NUM)
#define SET_COOLER_PWMCCR(NUM)  SET_PWM_CH2(NUM)
#define SET_LEDB_PWMCCR(NUM)  SET_PWM_CH4(NUM)

#define WRITE_LEDR(BIT) GPIO_WriteBit(LEDR_PORT,LEDR_PIN,BIT) 
#define LED_ON  Bit_SET
#define LED_OFF Bit_RESET

/* Global Variable */
vu8 val;
char gear = 80;//默认功率，最高100

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    SystemCoreClockUpdate();
    Delay_Init();
    keyInit();
    ledInit();
    timInit(ARR,24-1);//100HZ,频率太高两线无刷电机会很吵；
    ADC_Function_Init();
#if (SDI_PRINT == SDI_PR_OPEN)
    SDI_Printf_Enable();
#else
    USART_Printf_Init(115200);
#endif

    while(1)
    {
        if (GPIO_ReadInputDataBit(KEY1PORT,KEY1PIN) == RESET)//key-
        {
            Delay_Ms(20);
            if (GPIO_ReadInputDataBit(KEY1PORT,KEY1PIN) == RESET){
                gear--;

            }
        }
        if (GPIO_ReadInputDataBit(KEY2PORT,KEY2PIN) == RESET)//key+
        {
            Delay_Ms(20);
            if (GPIO_ReadInputDataBit(KEY2PORT,KEY2PIN) == RESET){
                gear++;
            }
        }
        gear = _constrain(gear,0,100);
        u16 temp = (float)gear * 0.01 * ARR;
        temp = _constrain(temp,0,ARR);

        float Vbus;
        Vbus = getVbusVolt();
        if (Vbus>VBUS_TARGET*1.2 || Vbus < VBUS_TARGET*0.8){
            WRITE_LEDR(LED_ON);
            temp = 0;

        }
        else{
            WRITE_LEDR(LED_OFF);
        }
        SET_COOLER_PWMCCR(temp);
        SET_LEDB_PWMCCR(temp);
        temp += POWER_DIFFERENCE;
        temp = _constrain((temp),MIN_FAN_CCR,ARR);//PWM调制两线无刷电机，低占空比会很吵
        SET_FAN_PWMCCR(temp);

        printf("gear:%d,Vbus:%dmv\r\n",gear,(u16)(Vbus*1000));
        Delay_Ms(5);
    }
}

void keyInit()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin = KEY1PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(KEY1PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY2PIN;
    GPIO_Init(KEY2PORT, &GPIO_InitStructure);

}
void ledInit()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin = LEDR_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(LEDR_PORT, &GPIO_InitStructure);
}

void timInit(u16 arr , u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    TIM_OCInitTypeDef TIM_OCInitStructure={0};
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2 , ENABLE );

    GPIO_InitStructure.GPIO_Pin = FAN_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;
    GPIO_Init( FAN_PORT, &GPIO_InitStructure );
    GPIO_InitStructure.GPIO_Pin = COOLER_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;
    GPIO_Init( COOLER_PORT, &GPIO_InitStructure );

    GPIO_InitStructure.GPIO_Pin = LEDB_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;
    GPIO_Init(LEDB_PORT, &GPIO_InitStructure);

    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 499;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init( TIM2, &TIM_OCInitStructure );
    TIM_OC2Init( TIM2, &TIM_OCInitStructure );
    TIM_OC4Init( TIM2, &TIM_OCInitStructure );

    TIM_CtrlPWMOutputs(TIM2, ENABLE );
    TIM_OC1PreloadConfig( TIM2, TIM_OCPreload_Disable );
    TIM_ARRPreloadConfig( TIM2, ENABLE );
    TIM_Cmd( TIM2, ENABLE );
}

void ADC_Function_Init(void)
{
    ADC_InitTypeDef  ADC_InitStructure = {0};
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);

    GPIO_InitStructure.GPIO_Pin = A2_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(A2_PORT, &GPIO_InitStructure);

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);


    ADC_Calibration_Vol(ADC1, ADC_CALVOL_50PERCENT);
    ADC_Cmd(ADC1, ENABLE);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_30Cycles);

    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_ADC_Val()
{
    u16 val;

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

    val = ADC_GetConversionValue(ADC1);

    return val;
}
float getVbusVolt()
{
    float temp;
    temp = (float)Get_ADC_Val();
    temp = temp*3.3/1024.f
    /13.f*113.f//调整采样电阻调整此处
    ;
    return temp;
}
